﻿using System;
using System.IO;
using System.Net;
using System.Threading;
using IndicoInterface;

namespace IndicoAutoDownloader
{
    class Program
    {
        /// <summary>
        /// Auto-download a conference.
        /// Usage: IndicoAutoDownloader <url-of-conf> <location to save>
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            if (args.Length != 2)
            {
                Usage();
                return;
            }
            string url = args[0];
            string location = args[1];

            //
            // Make sure this is a real meeting URL
            //

            var meeting = new AgendaInfo(url);
            var meetingSnapshot = meeting.GetNormalizedConferenceData();
            Console.WriteLine("Fetching files for '{0}'.", meetingSnapshot.Title);

            //
            // Now actually run a search on the files.
            //

            var dir = new DirectoryInfo(location);

            var t = new Timer(o => RunUpdate(meeting, dir), null, 0, 5 * 60 * 1000);

            while (true)
                Thread.Sleep(1000);
        }

        private static bool _inprogress = false;

        private static void RunUpdate(AgendaInfo meeting, DirectoryInfo dir)
        {
            if (_inprogress)
                return;
            _inprogress = true;

            try
            {
                Console.WriteLine("Running check {0}", DateTime.Now.ToString());
                var meetingSnapshot = meeting.GetNormalizedConferenceData();
                UpdateMeetingFiles(meetingSnapshot, dir);
            }
            catch (Exception e)
            {
                Console.WriteLine("Failed to update: {0} - {1}", e.Message, e.StackTrace);
            }
            finally
            {
                _inprogress = false;
            }
        }

        /// <summary>
        /// Look at what exists in the output directory and what files are in the meeting. Download the ones that are
        /// needed.
        /// </summary>
        /// <param name="meetingSnapshot"></param>
        /// <param name="dir"></param>
        private static void UpdateMeetingFiles(IndicoInterface.SimpleAgendaDataModel.Meeting meetingSnapshot, DirectoryInfo dir)
        {
            DownloadTalks(meetingSnapshot.MeetingTalks, dir);
            foreach (var session in meetingSnapshot.Sessions)
            {
                var newDir = session.DirectoryName(dir);
                DownloadSession(session, newDir);
            }
        }

        /// <summary>
        /// Download talks in a session.
        /// </summary>
        /// <param name="session"></param>
        /// <param name="newDir"></param>
        private static void DownloadSession(IndicoInterface.SimpleAgendaDataModel.Session session, DirectoryInfo newDir)
        {
            DownloadTalks(session.Talks, newDir);
        }

        /// <summary>
        /// Download the list of talks into the current directory.
        /// </summary>
        /// <param name="talks"></param>
        /// <param name="dir"></param>
        private static void DownloadTalks(IndicoInterface.SimpleAgendaDataModel.Talk[] talks, DirectoryInfo dir)
        {
            if (talks == null)
                return;

            foreach (var t in talks)
            {
                DownloadTalk(t, dir);
            }

        }

        /// <summary>
        /// Download the slides, if we need to, for a single talk.
        /// </summary>
        /// <param name="t"></param>
        /// <param name="dir"></param>
        private static void DownloadTalk(IndicoInterface.SimpleAgendaDataModel.Talk t, DirectoryInfo dir)
        {
            var talkPrefix = t.NamePrefix();

            // The main URL for the talk
            if (t.SlideURL != null)
            {
                DownloadTalk(t.SlideURL, talkPrefix, dir);
            }
        }

        private static WebClient _wc = new WebClient();

        /// <summary>
        /// Download a file at the other end of a URL.
        /// </summary>
        /// <param name="p"></param>
        /// <param name="talkPrefix"></param>
        /// <param name="dir"></param>
        private static void DownloadTalk(string urlString, string talkPrefix, DirectoryInfo dir)
        {

            // Load up the last modified date

            string lastModDate = "";
            var lastModDateTokenFile = new FileInfo(Path.Combine(dir.FullName, "zTokens", string.Format("{0}.txt", talkPrefix)));
            if (lastModDateTokenFile.Exists)
            {
                try
                {
                    lastModDate = File.ReadAllLines(lastModDateTokenFile.FullName)[0];
                }
                catch
                {
                }
            }

            // Load up the headers and see what things look like.

            FileInfo destFile = null;
            var req = HttpWebRequest.Create(urlString);
            req.Method = "HEAD";
            using (System.Net.WebResponse resp = req.GetResponse())
            {
                var lmod = resp.Headers.Get("Last-Modified");
                if (lmod == lastModDate)
                    return;
                lastModDate = lmod;

                var ftype = resp.ContentType;
                string extension = "";
                if (ftype == "application/pdf")
                {
                    extension = "pdf";
                }
                else if (ftype == "application/vnd.openxmlformats-officedocument.presentationml.presentation")
                {
                    extension = "ppt";
                }
                else if (ftype == "application/vnd.ms-powerpoint")
                {
                    extension = "pptx";
                }
                else
                {
                    Console.WriteLine(string.Format("Don't know what to do with mime-type '{0}'", ftype));
                    return;
                }
                destFile = new FileInfo(Path.Combine(dir.FullName, string.Format("{0}.{1}", talkPrefix, extension)));
            }

            // And get the file.

            if (lastModDate == "")
            {
                Console.WriteLine("Downloading {0}.", destFile.Name);
            }
            else
            {
                Console.WriteLine("Updating {0}", destFile.Name);
            }

            if (!destFile.Directory.Exists)
                destFile.Directory.Create();
            _wc.DownloadFile(urlString, destFile.FullName);

            // And save the token.

            if (!lastModDateTokenFile.Directory.Exists)
                lastModDateTokenFile.Directory.Create();
            File.WriteAllLines(lastModDateTokenFile.FullName, new string[] { lastModDate });
        }

        /// <summary>
        /// Dump out usage info to the console.
        /// </summary>
        private static void Usage()
        {
            Console.WriteLine("InidcoAutoDownloader <url-of-conf> <location-to-save>");
        }
    }
}
